import sys

import numpy
from PyQt5.QtCore import Qt, QRect, QSize
from PyQt5.QtGui import QCursor, QColor
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QFileDialog, QCheckBox, QListWidgetItem

import pyqtgraph
import pyqtgraph.exporters

from main_win.visual import Ui_visualwin

PADDING = 10


class visual_window(QMainWindow, Ui_visualwin):
    def __init__(self, parent=None):
        super(visual_window, self).__init__(parent)
        self.setupUi(self)
        # no border and transparent
        self.m_flag = False
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.SHADOW_WIDTH = 0
        self.isLeftPressDown = False
        self.dragPosition = 0
        self.dir = 8

        self.minButton.clicked.connect(self.showMinimized)
        self.closeButton.clicked.connect(self.close)
        self.clearButton.clicked.connect(self.cleardata)

        # paint edit
        pyqtgraph.setConfigOptions(leftButtonPan=False, antialias=True)
        self.plt = pyqtgraph.plot(background=QColor(31,31,31))
        # axis name
        self.plt.setLabel(axis='left',text='Quantity')
        self.plt.setLabel(axis='bottom',text='Time')
        # add to window
        self.gridLayout.addWidget(self.plt)
        # line chart background
        self.plt.setStyleSheet("padding-left:8px;padding-right:10px;background-color:#1f1f1f")
        # show grid
        self.plt.showGrid(True, True)
        self.plt.setMouseEnabled(x=False, y=False)
        # add legends on line chart
        self.plt.addLegend()
        # colors of line
        self.pencolor = ['#0a64a4','#ffbe00','#ff4500','#65a5d1','#ffffff',
                         '#ffdb73','#ff7340','#3399FF','#9933ff','#ff33ff']
        # different lines
        self.line = []
        # datas for lines
        self.data = []
        # show which line
        self.ifshow = []
        # line name to num id
        self.mp = {}
        # line quantity
        self.cnt = 0
        # paint tine
        self.mytot = 0

    def cleardata(self):
        self.listWidget.clear()
        self.line = []
        self.data = []
        self.ifshow = []
        self.mp = {}
        self.cnt = 0
        self.plt.clear()
        self.mytot = 0

    def region(self, cursorGlobalPoint):

        rect = self.rect()
        tl = self.mapToGlobal(rect.topLeft())
        rb = self.mapToGlobal(rect.bottomRight())

        x = cursorGlobalPoint.x()
        y = cursorGlobalPoint.y()
        if tl.x() + PADDING >= x >= tl.x() and tl.y() + PADDING >= y >= tl.y():
            self.dir = 4
            self.setCursor(QCursor(Qt.SizeFDiagCursor))
        elif rb.x() - PADDING <= x <= rb.x() and rb.y() - PADDING <= y <= rb.y():
            self.dir = 6
            self.setCursor(QCursor(Qt.SizeFDiagCursor))
        elif tl.x() + PADDING >= x >= tl.x() and rb.y() - PADDING <= y <= rb.y():
            self.dir = 5
            self.setCursor(QCursor(Qt.SizeBDiagCursor))
        elif rb.x() >= x >= rb.x() - PADDING and tl.y() <= y <= tl.y() + PADDING:
            self.dir = 7
            self.setCursor(QCursor(Qt.SizeBDiagCursor))
        elif tl.x() + PADDING >= x >= tl.x():
            self.dir = 2
            self.setCursor(QCursor(Qt.SizeHorCursor))
        elif rb.x() >= x >= rb.x() - PADDING:
            self.dir = 3
            self.setCursor(QCursor(Qt.SizeHorCursor))
        elif tl.y() <= y <= tl.y() + PADDING:
            self.dir = 0
            self.setCursor(QCursor(Qt.SizeVerCursor))
        elif rb.y() >= y >= rb.y() - PADDING:
            self.dir = 1
            self.setCursor(QCursor(Qt.SizeVerCursor))
        else:
            self.dir = 8
            self.setCursor(QCursor(Qt.ArrowCursor))

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.isLeftPressDown = False
            if self.dir != 8:
                self.releaseMouse()
                self.setCursor(QCursor(Qt.ArrowCursor))

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.isLeftPressDown = True
            if self.dir != 8:
                self.mouseGrabber()
            else:
                self.dragPosition = event.globalPos() - self.frameGeometry().topLeft()

    def mouseMoveEvent(self, event):
        gloPoint = event.globalPos()
        rect = self.rect()
        tl = self.mapToGlobal(rect.topLeft())
        rb = self.mapToGlobal(rect.bottomRight())

        if not self.isLeftPressDown:
            self.region(gloPoint)
        else:
            if self.dir != 8:
                remove = QRect(tl, rb)
                if self.dir == 2:
                    if rb.x() - gloPoint.x() <= self.minimumWidth():
                        remove.setX(tl.x())
                    else:
                        remove.setX(gloPoint.x())
                elif self.dir == 3:
                    remove.setWidth(gloPoint.x() - tl.x())
                elif self.dir == 0:
                    if rb.y() - gloPoint.y() <= self.minimumHeight():
                        remove.setY(tl.y())
                    else:
                        remove.setY(gloPoint.y())
                elif self.dir == 1:
                    remove.setHeight(gloPoint.y() - tl.y())
                elif self.dir == 4:
                    if rb.x() - gloPoint.x() <= self.minimumWidth():
                        remove.setX(tl.x())
                    else:
                        remove.setX(gloPoint.x())
                    if rb.y() - gloPoint.y() <= self.minimumHeight():
                        remove.setY(tl.y())
                    else:
                        remove.setY(gloPoint.y())
                elif self.dir == 7:
                    remove.setWidth(gloPoint.x() - tl.x())
                    remove.setY(gloPoint.y())
                elif self.dir == 5:
                    remove.setX(gloPoint.x())
                    remove.setHeight(gloPoint.y() - tl.y())
                elif self.dir == 6:
                    remove.setWidth(gloPoint.x() - tl.x())
                    remove.setHeight(gloPoint.y() - tl.y())
                else:
                    pass
                self.setGeometry(remove)
            else:
                self.move(event.globalPos() - self.dragPosition)
                event.accept()

    # refresh the line chart and options
    def refresh(self, statistic_dic, tot):
        try:
            self.mytot += 1
            statistic_dic = sorted(statistic_dic.items(), key=lambda x: x[1], reverse=True)
            # select objects whose quantity > 0
            statistic_dic = [i for i in statistic_dic if i[1] > 0]
            # check existed lines with new data
            for i in statistic_dic:
                flag = 0
                # object already exist ,add new quantity
                for key in self.mp:
                    if key == str(i[0]):
                        flag = 1
                        self.data[self.mp[key]].append(i[1])
                # object no exist ,add new line
                if flag == 0:
                    self.mp[str(i[0])] = self.cnt
                    # pre-data all set 0
                    if self.mytot == 1:
                        self.data.append([i[1]])
                    else:
                        self.data.append([0])
                        for val in range(3, self.mytot):
                            self.data[self.cnt].append(0)
                        self.data[self.cnt].append(i[1])
                    # add new option box
                    self.addNewBox(str(i[0]))
                    # add new line
                    self.line.append(self.plt.plot(pen=self.pencolor[self.cnt], name=str(i[0])))
                    self.cnt += 1
            # set the object's data among the lines who have no new data as 0
            for key in self.mp:
                flag = 0
                for i in statistic_dic:
                    if key == str(i[0]):
                        flag = 1
                if flag == 0:
                    self.data[self.mp[key]].append(0)
            # check the option box
            for checkbox in self.listWidget.findChildren(QCheckBox):
                if checkbox.isChecked():
                    self.setshow(checkbox.text(), 1)
                else:
                    self.setshow(checkbox.text(), 0)
            # paint the lines
            for i in range(0, self.cnt-1):
                # show
                if self.ifshow[i] == 1:
                    self.line[i].setData(self.data[i])
                # not show
                else :
                    self.line[i].clear()
        except Exception as e:
             self.statistic_msg('%s' % e)

    def addNewBox(self, name):
        box = QCheckBox(name)
        # default : show the line
        box.setChecked(True)
        # color correspond to line color
        box.setStyleSheet("font-size:20px;color:"+self.pencolor[self.cnt])
        item = QListWidgetItem()
        item.setSizeHint(QSize(130,40))
        self.listWidget.addItem(item)
        self.listWidget.setItemWidget(item, box)
        # default : show the line
        self.ifshow.append(1)

    # set show or not flag according to option boxes
    def setshow(self, txt, flag):
        for key in self.mp:
            if key == txt:
                self.ifshow[self.mp[key]] = flag

    # use api to export the result img
    def export(self):
        filepath, _ = QFileDialog.getSaveFileName(self, 'Save Result', 'Visual.png', "*.*")
        exporter = pyqtgraph.exporters.ImageExporter(self.plt.plotItem)
        exporter.export(filepath)

    def statistic_msg(self, msg):
        self.statistic_label.setText(msg)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    a = visual_window()
    a.show()
    sys.exit(app.exec_())
